#define ROWS1 3
#define COLS1 3
#define ROWS2 3
#define COLS2 3
/**
 * @brief 计算两个矩阵的乘积，并将结果存储在第三个矩阵中。
 *
 * 该函数实现了两个矩阵的乘法运算，其中矩阵 mat1 的大小为 ROWS1 x COLS1，
 * 矩阵 mat2 的大小为 ROWS2 x COLS2，结果矩阵 res 的大小为 ROWS1 x COLS2。
 * 在计算过程中，每个元素的计算结果都会通过 printf 打印出来，以便调试和验证。
 *
 * @param mat1 第一个输入矩阵，大小为 ROWS1 x COLS1。
 * @param mat2 第二个输入矩阵，大小为 ROWS2 x COLS2。
 * @param res 输出矩阵，存储 mat1 和 mat2 的乘积，大小为 ROWS1 x COLS2。
 */
void matchenfa(int mat1[ROWS1][COLS1], int mat2[ROWS2][COLS2], int res[ROWS1][COLS2]) {
    int i, j, k;
    for (i = 0; i < ROWS1; i++) {
        for (j = 0; j < COLS2; j++) {
            res[i][j] = 0;
            res[i][j] = 0;
            for (k = 0; k < COLS1; k++) {

                res[i][j] += mat1[i][k] * mat2[k][j];
                
                printf("mat1[%d][%d] = %d, mat2[%d][%d] = %d, res[%d][%d] = %d\n", i, k, mat1[i][k], k, j, mat2[k][j], i, j, res[i][j]);
            }
        }
    }
}


/**
 * 从给定的字符串中提取数字，并将这些数字存储到一个整数数组中。
 *
 * @param str   输入的字符串，包含数字和其他字符。
 * @param arr   用于存储提取出的数字的整数数组。
 * @param size  用于返回提取出的数字的数量。
 */
void extractNumbers(char *str, int *arr, int *size) {
    int count = 0;      // 记录提取出的数字的数量
    int num = 0;        // 当前正在提取的数字
    int isNum = 0;      // 标志当前字符是否为数字

    // 遍历字符串中的每个字符
    int count = 0;
    int num = 0;
    int isNum = 0;
    for (int i = 0; i < strlen(str); i++) {
        // 如果当前字符是数字
        if (str[i] >= '0' && str[i] <= '9') {
            // 将当前数字字符转换为整数并累加到num中
            num = num * 10 + (str[i] - '0');
            isNum = 1;  // 设置标志为1，表示当前字符是数字
            isNum = 1;
        } else {
            // 如果当前字符不是数字，且前一个字符是数字
            if (isNum) {
                // 将提取出的数字存储到数组中
                arr[count] = num;
                count++;  // 数字数量加1
                num = 0;  // 重置当前数字
                isNum = 0;  // 重置标志
                count++;
                num = 0;
                isNum = 0;
            }
        }
    }
    // 如果字符串的最后一个字符是数字，将其存储到数组中
    if (isNum) {
        arr[count] = num;
        count++;
    }
    // 返回提取出的数字的数量
    *size = count;
}


/**
 * @brief 移除数组中的所有零元素，并将非零元素移动到数组的前面。
 *
 * 该函数遍历输入的整数数组，将非零元素移动到数组的前面，并更新数组的长度，
 * 以去掉所有零元素。函数通过指针参数返回新的数组长度。
 *
 * @param arr 输入的整数数组。
 * @param n 指向整数变量的指针，表示数组的长度。函数执行后，该变量将更新为去掉零元素后的数组长度。
 */
void removeZeros(int arr[], int *n) {
    int count = 0; // 用于记录非零元素的数量

    // 遍历数组
    for (int i = 0; i < *n; i++) {
        // 如果当前元素不是0，则将其移动到前面
        if (arr[i] != 0) {
            arr[count] = arr[i]; // 将非零元素移动到数组的前面
            count++; // 增加非零元素的计数
        }
    }

    // 更新数组的长度，去掉所有0元素后的长度
    *n = count; // 将非零元素的数量赋值给原数组的长度，即去掉所有0元素后的长度
}


// 函数声明：removeChar
// 参数：
//   str: 指向字符数组的指针，表示要处理的字符串
//   remove: 要从字符串中移除的字符
//   n: 指向整数的指针，表示字符串的当前长度，函数执行后更新为移除字符后的新长度
void removeChar(char *str, char remove, int *n) {
    // 初始化计数器count，用于记录移除指定字符后的新字符串长度
    int count = 0;
    // 遍历字符串的每一个字符
    for (int i = 0; i < *n; i++) {
        // 如果当前字符不等于要移除的字符
        if (str[i] != remove) {
            // 将当前字符复制到新位置
            str[count] = str[i];
            // 更新计数器，表示新字符串的长度增加
            count++;
        }
    }
    // 更新字符串的实际长度为移除指定字符后的新长度
    *n = count;
}

// 函数声明：removeNullChars
// 功能：移除字符串中的所有空字符（'\0'）
// 参数：char *str - 指向待处理字符串的指针
void removeNullChars(char *str) {
    // 变量声明：count
    // 用途：用于记录非空字符的数量，同时也是新字符串的索引
    int count = 0;
    // for循环遍历字符串
    // 条件：str[i] != '\0'，即遍历到字符串的末尾（'\0'）为止
    for (int i = 0; str[i]; i++) {
        // 如果当前字符不是空字符（'\0'）
        if (str[i] != '\0') {
            // 将当前字符复制到字符串的前count位置
            str[count++] = str[i];
        }
    }
    // 在处理完所有非空字符后，将字符串末尾设置为空字符（'\0'）
    // 以确保字符串正确终止
    str[count] = '\0';
}

/**
 * @brief 从给定的日期字符串中提取年、月、日信息。
 *
 * 该函数使用sscanf函数从输入的日期字符串中解析出年、月、日的整数值，
 * 并将它们存储在对应的指针变量中。
 *
 * @param date_str 输入的日期字符串，格式应为"YYYY-MM-DD"。
 * @param year 指向存储年份的整型变量的指针。
 * @param month 指向存储月份的整型变量的指针。
 * @param day 指向存储日期的整型变量的指针。
 *
 * @return 无返回值。
 */
void inputDate(const char *date_str, int *year, int *month, int *day) {

    sscanf(date_str, "%d-%d-%d", year, month, day);
}


/**
 * @brief 检查给定的日期是否有效。
 *
 * 该函数接收年、月、日作为参数，判断该日期是否为一个有效的日期。
 * 首先，函数会判断给定的年份是否为闰年，如果是闰年则将二月的天数设为29天。
 * 然后，函数会检查月份是否在1到12之间，以及日期是否在对应月份的天数范围内。
 * 如果日期无效，则返回0；如果日期有效，则返回1。
 *
 * @param year 年份
 * @param month 月份
 * @param day 日期
 * @return int 日期是否有效，0表示无效，1表示有效
 */
int validDate(int year, int month, int day) {

    int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    // 判断是否为闰年，如果是闰年则将二月的天数设为29天
    if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
        printf("闰年\n");
        days[1] = 29;
    }

    // 检查月份是否在1到12之间，以及日期是否在对应月份的天数范围内
    if (month < 1 || month > 12 || day < 1 || day > days[month - 1]) {
        return 0;
    }
    return 1;
}


/**
 * @brief 将输入的日期字符串转换为"dd/mm/yyyy"的格式
 *
 * 该函数接收一个日期字符串和一个字符数组，将输入的日期字符串解析为年、月、日，
 * 然后将这些信息格式化为"dd/mm/yyyy"的形式，并存储到提供的字符数组中。
 *
 * @param date_str 输入的日期字符串，格式由具体实现决定
 * @param decdate  用于存储转换后的日期字符串的字符数组
 */
void convertDate(const char *date_str, char *decdate) {
    int year, month, day;

    // 调用函数inputDate解析输入的日期字符串，获取年、月、日信息
    inputDate(date_str, &year, &month, &day);

    // 将年、月、日格式化为"dd/mm/yyyy"的形式，并存储到decdate中
    sprintf(decdate, "%02d/%02d/%04d", day, month, year);
}



#define SIZE_NUM 100 // 定义常量SIZE_NUM，表示成绩数组的大小
// 函数randnumscore：生成随机成绩并返回成绩数组的指针
int *randnumscore()
{
    // int array[50]; // 注释掉的代码，原意可能是定义一个大小为50的数组
    int *array = (int *)malloc(SIZE_NUM * sizeof(int)); // 动态分配一个大小为SIZE_NUM的整型数组
    srand(time(0)); // 设置随机数种子，使用当前时间

    // 循环生成随机成绩并存储到数组中
    for (int i = 0; i < SIZE_NUM; i++)
    {
        array[i] = rand() % 100 + 1; // 生成1到100之间的随机数
    }

    // 打印生成的成绩列表
    printf("成绩列表: [");
    for (int i = 0; i < SIZE_NUM; i++)
    {
        printf("%d， ", array[i]); // 打印每个成绩
    }
    printf("]\n"); // 结束成绩列表的打印

    return array; // 返回成绩数组的指针
}

// 函数cal：计算成绩数组的平均值和最大值
void cal(int *arr, int n, int *avg, int *max)
{
    int sum = 0; // 初始化总和为0
    *max = arr[0]; // 初始化最大值为数组的第一个元素

    // 循环遍历数组，计算总和和最大值
    for (int i = 0; i < n; i++)
    {
        sum += arr[i]; // 累加每个成绩
        if (arr[i] > *max) // 如果当前成绩大于最大值
        {
            *max = arr[i]; // 更新最大值
        }
    }

    *avg = sum / n; // 计算平均值
}

// 函数showScorce：显示成绩的分段统计
void showScorce(int *arr, int n)
{
    int fenduan[10] = {0}; // 初始化分段统计数组，大小为10

    // 循环遍历成绩数组，进行分段统计
    for (int i = 0; i < n; i++)
    {
        fenduan[(arr[i] - 1) / 10]++; // 根据成绩范围增加对应分段的计数
    }
    printf("\n分段统计:\n"); // 打印分段统计标题
    // 循环打印每个分段的统计结果
    for (int i = 0; i < 10; i++)
    {
        printf("%d-%d: ", i * 10 + 1, (i + 1) * 10); // 打印分段范围
        for (int j = 0; j < fenduan[i]; j++) // 打印每个分段的成绩数量
        {
            printf("*"); // 使用星号表示成绩数量
        }
        printf("(%d)", fenduan[i]); // 打印具体数量
        printf("\n"); // 换行
    }
}


/**
 * @brief 检查用户输入是否为整数，并返回该整数。
 *
 * 该函数通过循环提示用户输入一个整数，如果用户输入的不是整数，则提示错误并要求重新输入。
 * 当用户输入一个整数时，函数会输出该整数并返回它。
 *
 * @return 用户输入的整数。
 */
int checkisnum()
{

    // 定义一个整型变量i
    int i;

    // 无限循环
    while (1)
    {
        // 提示用户输入一个数字
        printf("请输入一个数字: ");

        // 如果用户输入的是一个整数
        if (scanf("%d", &i) == 1)
        {
            // 输出用户输入的数字
            printf("输入的数字是： %d\n", i);

            // 跳出循环
            break;
        }
        else
        {
            // 输出错误提示
            printf(" 输入错误，请重新输入！\n");

            // 清空输入缓冲区
            while (getchar() != '\n');
        }
    }

    // 返回用户输入的数字
    return i;
}

